package com.sz.common.base.dao.schema;

import com.sz.common.base.dao.Dao;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.mapping.ResultMapping;
import org.apache.ibatis.type.JdbcType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Package: com.sz.common.base.dao.schema <br>
 * Function: TODO: ADD FUNCTION <br>
 * Author: Charles. <br>
 * Date: 2017-02-24 09:54:00.
 */
@Service
public class TableSchemaLoader {
    @Autowired
    Dao dao;

    private Map<String, TableSchema> schemaCaches = new HashMap<>();

    public TableSchema loadFromMapperNs(String tableName, String namespace) {
        TableSchema schema = schemaCaches.get(tableName);
        if (schema != null) {
            return schema;
        }
        if (!StringUtils.hasLength(namespace)) {
            throw new IllegalArgumentException("namespace cannot be empty");
        }
        String defaultResultMapperId = namespace + ".BaseResultMap";
        return this.loadFromResultMapper(tableName, defaultResultMapperId);
    }

    public TableSchema loadFromResultMapper(String tableName, String resultMapperId) {
        TableSchema schema = schemaCaches.get(tableName);
        if (schema != null) {
            return schema;
        }

        if (!StringUtils.hasLength(resultMapperId)) {
            throw new IllegalArgumentException("resultMapperId cannot be empty");
        }
        ResultMap resultMap = this.dao.getConfiguration().getResultMap(resultMapperId);
        if (resultMap == null) {
            throw new IllegalArgumentException("cannot find result mapper:" + resultMapperId);
        }
        return this.loadFromResultMapper(tableName, resultMap);
    }

    private TableSchema loadFromResultMapper(String tableName, ResultMap resultMap) {
        if (!StringUtils.hasLength(tableName)) {
            throw new IllegalArgumentException("table name cannot be empty");
        }
        if (resultMap == null) {
            throw new IllegalArgumentException("resultMap cannot be empty");
        }
        TableSchema schema = new TableSchema(tableName);

        List<ResultMapping> list = resultMap.getResultMappings();
        if (list != null && list.size() > 0) {
            for (ResultMapping mapping : list) {
                String columnName = mapping.getColumn();
                JdbcType jdbcType = mapping.getJdbcType();

                FieldSchema fieldSchema = new FieldSchema(columnName, jdbcType);
                schema.getFields().add(fieldSchema);
            }
        }

        List<ResultMapping> idList = resultMap.getIdResultMappings();
        if (idList != null && idList.size() > 0) {
            for (ResultMapping mapping : idList) {
                String primaryKey = mapping.getColumn();
                schema.addPrimaryKeyName(primaryKey);
            }
        }

        schemaCaches.put(tableName, schema);
        return schema;
    }

    public TableSchema loadFromDb(String tableName) {
        TableSchema schema = schemaCaches.get(tableName);
        if (schema != null) {
            return schema;
        }
        if (!StringUtils.hasLength(tableName)) {
            throw new IllegalArgumentException("table name cannot be empty");
        }

        schema = new TableSchema(tableName);
        List<Map> list = this.dao.findForList("CommonMapper.commonSelectTableSchema", tableName, Map.class);

        if (list != null && list.size() > 0) {
            for (Map map : list) {
                String columnName = (String) map.get("Field");
                String dbType = (String) map.get("Type");
                JdbcType jdbcType = convertToJdbcType(dbType);
                if (StringUtils.hasLength(columnName) && jdbcType != null) {
                    FieldSchema fieldSchema = new FieldSchema(columnName, jdbcType);
                    schema.getFields().add(fieldSchema);
                }
            }
        }

        schemaCaches.put(tableName, schema);
        return schema;
    }

    private JdbcType convertToJdbcType(String typeString) {
        if (typeString != null && typeString.trim().length() > 0) {
            typeString = typeString.trim();
            int index = typeString.indexOf(" ");
            if (index > 0) {
                typeString = typeString.substring(0, index);
            }
            index = typeString.indexOf("(");
            if (index > 0) {
                typeString = typeString.substring(0, index);
            }
            try {
                return JdbcType.valueOf(typeString.toUpperCase());
            } catch (IllegalArgumentException ex) { //ignore
            }
        }
        return null;
    }
}
